package nl.ajonker.railroad.dl;

import nl.ajonker.railroad.ui.drawcommand.DrawCommand;

public abstract class Rail {
	private enum Direction {
		FORWARD, REVERSE
	}

	private static final int DEFAULT_LENGTH = 10;
	private final int length;
	private final DrawCommand drawCommand;

	private final Connector connectorA = new Connector(Direction.FORWARD);
	private final Connector connectorB = new Connector(Direction.REVERSE);

	private Integer trainPosition;
	private Train train;
	private Direction direction;

	public static void connect(final Rail a, final Rail b) {
		a.connectorB.connect(b.connectorA);
		b.connectorA.connect(a.connectorB);
	}

	protected Rail(final DrawCommand command) {
		this(DEFAULT_LENGTH, command);
	}

	protected Rail(final int length, final DrawCommand drawCommand) {
		super();
		this.length = length;
		this.drawCommand = drawCommand;
	}

	public int getLength() {
		return length;
	}

	public DrawCommand getDrawCommand() {
		return drawCommand;
	}

	public void moveTrain() {
		if (direction == Direction.FORWARD)
			trainPosition++;
		else
			trainPosition--;
		if (trainPosition >= length) {
			connectorB.transfer(train);
			train = null;
			trainPosition = null;
		} else if (trainPosition < 0) {
			connectorA.transfer(train);
			train = null;
			trainPosition = null;
		}
	}

	public int getTrainPosition() {
		return (trainPosition == null) ? 0 : trainPosition;
	}

	public boolean hasTrain() {
		return train != null;
	}

	protected void accept(final Train t, final Direction direction) {
		this.direction = direction;
		trainPosition = 0;
		train = t;
		train.setRail(this);
	}

	class Connector {
		private Connector other;
		private final Direction d;

		Connector(final Direction d) {
			this.d = d;
		}

		private void connect(final Connector other) {
			this.other = other;
		}

		public void transfer(final Train t) {
			other.acceptTrain(t);
		}

		public boolean isConnected() {
			return other != null;
		}

		public void acceptTrain(final Train t) {
			accept(t, d);
		}
	}

	public void acceptTrain(final Train train) {
		connectorA.acceptTrain(train);
	}
}
